var Utils = this.Utils || (function ($) {
        var lazyAjax,
            keys,
            Iterator, collectNonEnumProps,
            curry,
            namespace,
            deeperObj,
            trim;

        lazyAjax = function () {
            var params = [].slice.call(arguments),
                url = params[ 0 ],
                type = 'GET',
                data = {},
                success;

            if ( params.length === 2 ) {
                if ( typeof params[ 1 ] === 'function' ) {
                    success = params[ 1 ];
                }
                else if ( typeof params[ 1 ] === 'object' ) {
                    data = params[ 1 ];
                }
            } else if ( params.length === 3 ) {
                success = params[ 2 ];

                if ( typeof params[ 1 ] === 'string' ) {
                    type = params[ 1 ];
                } else if ( typeof params[ 1 ] === 'object' ) {
                    data = params[ 1 ];
                }
            }

            $.ajax({
                url: url,
                dataType: 'html',
                type: type,
                data: data,
                beforeSend: function () {

                },
                success: function (json) {
                    if ( typeof json === 'string' ) {
                        try {
                            json = JSON.parse(json);
                        } catch ( e ) {
                            throw new TypeError('请确定接口的返回值格式');
                        }
                    }

                    if ( !!success && typeof success === 'function' ) {
                        success(json);
                    }
                },
                complete: function () {

                },
                error: function (data) {
                    console.info("error: " + data.responseText);
                }
            });
        };

        collectNonEnumProps = function (obj, keys) {
            var nonEnumerableProps = [ 'valueOf', 'isPrototypeOf', 'toString',
                'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString' ];
            var nonEnumIdx = nonEnumerableProps.length;
            var constructor = obj.constructor;
            var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;

            // Constructor is a special case.
            var prop = 'constructor';
            if ( _.has(obj, prop) && !_.contains(keys, prop) ) keys.push(prop);

            while ( nonEnumIdx-- ) {
                prop = nonEnumerableProps[ nonEnumIdx ];
                if ( prop in obj && obj[ prop ] !== proto[ prop ] && !_.contains(keys, prop) ) {
                    keys.push(prop);
                }
            }
        };

        keys = function (obj) {
            var objProto = Object.prototype,
                nativeKeys = objProto.keys,
                keys = [],
                hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');

            if ( !$.isPlainObject(obj) ) {
                return keys;
            }
            if ( !!nativeKeys ) {
                return nativeKeys(obj);
            }

            for ( var key in obj ) if ( objProto.hasOwnProperty.call(obj, key) ) {
                keys.push(key);
            }

            if ( hasEnumBug ) {
                collectNonEnumProps(obj, keys);
            }
            return keys;
        };

        /***
         * @author Bodhi
         * @date 2016/01/08
         * @param obj array or plainObject
         * @param type string
         * @param before callback
         * @returns object
         * @constructor
         */
        Iterator = function (obj, type, before) {
            'use strict';

            var jq = jQuery,
                i = 0,
                keyList = [],
                isPlainObject = jq.isPlainObject(obj);

            //if key is number and to sort.
            if ( !!type && type.toLowerCase() === 'asc' ) {
                keys.sort(function (x, y) {
                    if ( !isNaN(x) && !isNaN(y) ) {
                        return +x - +y;
                    }
                    return x - y;
                });
            }

            if ( $.isFunction(before) ) {
                before(keys);
            }

            return ({
                check: function () {
                    if ( !obj || (!isPlainObject) ) {
                        throw new TypeError('obj is not plain object.');
                    }
                    keyList = keys(obj);
                },
                idxCheck:function(){
                    if(i < 0 || i > keyList.length-1){
                        return undefined;
                    }
                    return this._index(i);
                },
                init: function () {
                    this.check();
                    return this;
                },
                hasNext: function () {
                    return i < keyList.length;
                },
                current: function () {
                    return this.idxCheck();
                },
                prev: function () {
                    --i;
                    return this.idxCheck();
                },
                next: function () {
                    ++i;
                    return this.idxCheck();
                },
                first: function () {
                    return this._index(0);
                },
                last: function () {
                    return this._index(keyList.length - 1);
                },
                index: function () {
                    return i;
                },
                toIndex: function (key) {
                    i = keyList.indexOf(key);
                    return this._index(i);
                },
                _index: function (idx) {
                    var key = keyList[ idx ];
                    return {key: key, value: obj[ key ]};
                }
            }.init());
        };

        curry = function () {

        };

        trim = function (str, sign) {
            return (function f(str, sign) {
                if ( typeof str === 'function' ) str = str();
                if ( str != undefined && ( sign === undefined || sign === '' || sign === 'ALL' || sign === 'A') ) {
                    return str.replace(/(^\s*)|(\s*$)/g, "");
                }

                sign = f(sign);

                if ( sign === 'L' ) {
                    return str.replace(/(^\s*)/g, "");
                } else if ( sign === 'R' ) {
                    return str.replace(/(\s*$)/g, "");
                }
            }(str, sign));
        };

        namespace = function (obj, str) {
            var i, keys, len, item,
                _obj = obj = obj || {};

            if ( typeof str === 'function' ) {
                str = str();
            }

            keys = str.split('.');

            for ( i = 0, len = keys.length; i < len; i++ ) {
                item = keys[ i ];
                _obj[ item ] = _obj[ item ] || {};
                _obj = _obj[ item ];
            }

            return _obj;
        };

        deeperObj = function (obj, str, time) {
            var _obj = obj || {},
                func = function () {
                    return (typeof str === 'function') && str() ||  (typeof str === 'string') && str;
                };

            while ( time-- ) {
                _obj = namespace(_obj, func());
            }

            return _obj;
        };

        return {
            keys: keys,
            lazyAjax: lazyAjax,
            Iterator: Iterator,
            trim: trim,
            curry: curry,
            namespace: namespace,
            deeperObj: deeperObj
        }
    }(jQuery));

